#include "core.h"
#include "UserMgr.h"
#include "AsioTcpLink.h"
#include "xGUID.h"
#include "DbExecute.h"
#include "LogMgr.h"
#include "ComputureMgr.h"
#include "ServerCore.h"
#include "PacketProcessor.h"

CUser::CUser( U64 uGuid )
: xObjBase(CGuidMgr::ENTITY_USER, uGuid)
, m_uRole_ID(0)
, m_uMagicID(0)
{

}

void CUser::SendKeyRCmd()
{
	MYTH::User_Key_R r;
	r.set_err_code(MYTH::Error_Success);
	xMSG msg(MYTH::CMD_User_Key_r, &r);

	CServerCore* core = CServerCore::getInstance();
	if (core)
	{
		core->SendMsg2Net(getBindGuid(), msg);
	}
}

void CUser::Save2DB()
{
	std::string in;
	user.SerializeToString(&in);
	CDbExecute db;

	std::string sql = "update user set user_data = ";
	std::string destStr;
	db.escape_string(in, destStr); 
	sql += "'";
	sql += destStr;
	sql += "' ";
	
	char temp[ 256 ] = {0};
	sprintf_s( temp, 256, " where user_id = %lld", user.user_id());

	sql += temp;

	db.execute(sql);
}

void CUser::LoadRoleList()
{
	if (user.IsInitialized())
	{
		//single role check
		if (user.role_list_size() > 0)
		{
			return ;
		}

		char sql[ 1024 ] = {0};
		CDbExecute db;
		sprintf_s( sql, 1024, "SELECT role_id,name,sex,job FROM `role` WHERE user_account='%s' AND bit_mask&1<>0 ORDER BY offline_time DESC",
			user.account_id().c_str());
		db.execute(sql);

		const CDbExecute::DATA_VEC_MAP& vData = db.GetDataMap();
		CDbExecute::DATA_VEC_MAP_ITRC itr = vData.begin();
		CDbExecute::DATA_VEC_MAP_ITRC itrE = vData.end();

		for ( ; itr != itrE; ++itr )
		{
			const CDbExecute::DATA_ROW_MAP& rowData = *itr;
			MYTH::SimpleRole* pSR = user.add_role_list();
			
			U32 uData = 0; U64 u_id = 0; std::string name;
			if (pSR)
			{
				if (rowData.GetValueU64("role_id", u_id)){
					pSR->set_role_id(u_id);
				}
				if (rowData.GetValueStr("name", name)){
					pSR->set_role_name(name);
				}
				if (rowData.GetValueUInt("sex", uData)){
					pSR->set_role_sex(uData);
				}
				if (rowData.GetValueUInt("job", uData)){
					pSR->set_role_job(uData);
				}
			}
		}
	}
}

void CUser::DestroyOldNet()
{
	net_link_ptr link_ptr = boost::dynamic_pointer_cast<CAsioTcpLink>(xNetObjBase::getNetObj(m_uBindGuid));
	if (link_ptr.get())
	{
		link_ptr->close();
	}
}

BOOL CUser::HaveRole(U64 role_id)
{
	U32 role_cnt = user.role_list_size();
	for (U32 i = 0; i < role_cnt; ++i)
	{
		if (user.role_list(i).role_id() == role_id)
		{
			return TRUE;
		}
	}

	return FALSE;
}
//---------------------------------------------------------------------------------------------------
CLoginUser::CLoginUser()
: xBase(CGuidMgr::ENTITY_LOGIN_USER)
{

}
//---------------------------------------------------------------------------------------------------
IMP_SINGLETON_CLASS(CUserMgr)

CUserMgr::CUserMgr()
{

}

CUserMgr::~CUserMgr()
{
	ClearUnorderMap(m_mapLoginUser);
	ClearUnorderMap(m_mapUsers);
}

CUser* CUserMgr::CreateUserByDB(const CDbExecute::DATA_ROW_MAP& rowData)
{
	std::string strRes;
	U64 user_id = 0; std::string account,pwd;
	rowData.GetValueU64( "user_id", user_id );
	CUser* pUser = new CUser( user_id );

	rowData.GetValueStr( "user_account", account );
	rowData.GetValueStr( "user_pwd", pwd );
	rowData.GetValueStr( "user_data", strRes );

	MYTH::User& user_data = pUser->user;
	user_data.ParseFromString(strRes);

	user_data.set_user_id(user_id);
	user_data.set_account_id(account);
	user_data.set_account_pwd(pwd);
	user_data.clear_gate_ip_port();
	user_data.clear_game_ip_port();

	std::pair<boost::unordered_map<std::string, CUser*>::iterator, bool> ins = 
		m_mapUsers.insert(boost::unordered_map<std::string, CUser*>::value_type(account, pUser));

	if( !ins.second )
	{
		delete pUser; pUser = NULL;
	}

	return pUser;
}

CUser* CUserMgr::LoadUserFromDB(U64 uGuid)
{
	xObjBase* pObj = xObjBase::getObj(uGuid);
	if ( pObj )
	{
		return dynamic_cast<CUser*>(pObj);
	}

	char sql[ 1024 ] = {0};
	CDbExecute db;
	sprintf_s( sql, 1024, "select user_id, user_account, user_pwd, user_data from user where user_id = %lld", uGuid);
	db.execute(sql);
	if ( db.GetData().size() )
	{
		const CDbExecute::DATA_ROW_MAP& rowData = db.GetRowMap();
		return CreateUserByDB(rowData);
	}
	return NULL;
}

CUser* CUserMgr::LoadUserFromDB(const std::string& str_account)
{
	CUser* pRet = getUser(str_account);
	if (pRet == NULL)
	{
		char sql[ 1024 ] = {0};
		CDbExecute db;
		sprintf_s( sql, 1024, "select user_id, user_account, user_pwd, user_data from user where user_account = '%s'", str_account.c_str());
		db.execute(sql);
		if ( db.GetData().size() )
		{
			const CDbExecute::DATA_ROW_MAP& rowData = db.GetRowMap();
			pRet = CreateUserByDB(rowData);
		}
	}

	return pRet;
}

void CUserMgr::LoadFromDB()
{
	char sql[ 1024 ] = {0};
	CDbExecute db;

	strcpy( sql, "select user_id, user_account, user_pwd, user_data from user");

	db.execute(sql);

	const CDbExecute::DATA_VEC_MAP& vData = db.GetDataMap();
	CDbExecute::DATA_VEC_MAP_ITRC itr = vData.begin();
	CDbExecute::DATA_VEC_MAP_ITRC itrE = vData.end();
	int nValue = 0;
	
	for ( ; itr != itrE; ++itr )
	{
		const CDbExecute::DATA_ROW_MAP& rowData = *itr;
		CreateUserByDB(rowData);
	}
}

CLoginUser* CUserMgr::GetLoginUser(const std::string& str_account)
{
	boost::unordered_map<std::string, CLoginUser*>::iterator it = m_mapLoginUser.find(str_account);
	if ( it != m_mapLoginUser.end() )
	{
		return it->second;
	}

	return NULL;
}

void CUserMgr::AddLoginUser(const std::string& str_account, CAsioTcpLink* pLink)
{
	RemoveLoginUser(str_account);
	if (pLink)
	{
		CLoginUser* pL = new CLoginUser;
		if (pL)
		{
			pL->setBindGuid(pLink->getGuid());
			pLink->setBindGuid(pL->getGuid());

			m_mapLoginUser.insert(std::pair<std::string, CLoginUser* >(str_account, pL));
			GAMELOGER->debug("AddLoginUser type=%s, ip=%s", 
				str_account.c_str(), pLink->getRemoteIPPort().c_str());
		}
	}
}

void CUserMgr::RemoveLoginUser(const std::string& str_account)
{
	boost::unordered_map<std::string, CLoginUser*>::iterator it = m_mapLoginUser.find(str_account);
	if ( it != m_mapLoginUser.end() )
	{
		CLoginUser* pL = it->second;
		delete pL;
		m_mapLoginUser.erase(it);
	}
}

CUser*  CUserMgr::getUser(const std::string& str_account)
{
	boost::unordered_map<std::string, CUser*>::iterator it = m_mapUsers.find(str_account);
	if ( it != m_mapUsers.end() )
	{
		return it->second;
	}

	return NULL;
}

CUser* CUserMgr::GateOnLoginR(MYTH::AccountLogin_R& cmd)
{
	CUser* pUser = getUser(cmd.account_id());
	if (pUser)
	{
		if (pUser->user.key() != cmd.key())
		{
			pUser->DestroyOldNet();
		}
		else
		{
			pUser->SendKeyRCmd();
		}
	}
	else
	{
		pUser = new CUser(cmd.user_id());
		if (pUser)
		{
			std::pair<boost::unordered_map<std::string, CUser*>::iterator, bool> ins = 
				m_mapUsers.insert(boost::unordered_map<std::string, CUser*>::value_type(cmd.account_id(), pUser));

			if( !ins.second )
			{
				delete pUser; pUser = NULL;
			}
		}
	}

	if (pUser)
	{
		pUser->user.set_user_id(cmd.user_id());
		pUser->user.set_account_id(cmd.account_id());
		pUser->user.set_game_ip_port(cmd.gate_ip_port());
		pUser->user.set_game_ip_port(cmd.game_ip_port());
		*(pUser->user.mutable_role_list()) = *cmd.mutable_role_list();
		pUser->user.set_key(cmd.key());

		CComputureMgr* pComputerMgr = CComputureMgr::getInstance();
		CSrvComputure* pC = pComputerMgr->getServer(cmd.game_ip_port());
		if (pC)
		{
			pUser->setm_uMagicID( pC->getBindGuid() );
		}
	}

	return pUser;
}

CUser* CUserMgr::CreateUserByKey(MYTH::User_Key& cmd)
{
	CUser* pUser = getUser(cmd.account_id());
	if (!pUser)
	{
		pUser = new CUser(cmd.user_id());
		if (pUser)
		{
			std::pair<boost::unordered_map<std::string, CUser*>::iterator, bool> ins = 
				m_mapUsers.insert(boost::unordered_map<std::string, CUser*>::value_type(cmd.account_id(), pUser));

			if( !ins.second )
			{
				delete pUser; pUser = NULL;
			}
		}
	}

	if (pUser)
	{
		pUser->user.set_user_id(cmd.user_id());
		pUser->user.set_account_id(cmd.account_id());
		pUser->user.set_key(cmd.key());
	}

	return pUser;
}